//        Copyright 2017 Muddi Walid
//
//        Licensed under the Apache License, Version 2.0 (the "License");
//        you may not use this file except in compliance with the License.
//        You may obtain a copy of the License at
//
//        http://www.apache.org/licenses/LICENSE-2.0
//
//        Unless required by applicable law or agreed to in writing, software
//        distributed under the License is distributed on an "AS IS" BASIS,
//        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//        See the License for the specific language governing permissions and
//        limitations under the License.

package com.muddzdev.styleabletoast.styleabletoast;

import ohos.agp.colors.RgbColor;
import ohos.agp.components.AttrHelper;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.DirectionalLayout;
import ohos.agp.components.LayoutScatter;
import ohos.agp.components.Text;
import ohos.agp.components.element.PixelMapElement;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.text.Font;
import ohos.agp.utils.Color;
import ohos.agp.utils.LayoutAlignment;
import ohos.agp.window.dialog.ToastDialog;
import ohos.app.Context;
import ohos.app.Environment;
import ohos.global.resource.NotExistException;
import ohos.global.resource.RawFileEntry;
import ohos.global.resource.Resource;
import ohos.global.resource.ResourceManager;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

/**
 * xinglu
 *
 * @since 2021-03-05
 */
public class StyleableToast extends DirectionalLayout {

    private static final int PADDING_VERTICAL = 11;
    private static final int PADDING_HORIZONTAL = 20;
    private static final int PADDING_NO_ICON = 20;
    private static final int ICON_SIZE = 19;
    private int cornerRadius;
    private Color defaultBackgroundColor = new Color(Constants.DEFAULT_BACKGROUND_COLOR);
    private Color backgroundColor;
    private Color strokeColor;
    private int strokeWidth;
    private int iconStart;
    private int iconEnd;
    private Color textColor;
    private String fontName;
    private int textSize;
    private boolean isTextSizeFromStyleXml = false;
    private boolean solidBackground;
    private boolean textBold;
    private String text;
    private int gravity;
    private Text textView;
    private Component rootLayout;
    private ShapeElement mBackgroundDrawable;
    private int mCornerRadius = Constants.CORNER_RADIUS;


    /**
     * 构造函数
     *
     * @param context
     * @param attrSet
     * @param styleName
     */
    public StyleableToast(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
    }

    /**
     * 构造函数
     *
     * @param context
     * @param text
     * @param style
     */
    public StyleableToast(Context context, String text, int style) {
        super(context);
        this.text = text;
    }

    /**
     * 初始化
     *
     * @param context
     * @param text
     * @param style
     * @return StyleableToast
     */
    public static StyleableToast makeText(Context context, String text, int style) {
        return new StyleableToast(context, text, style);
    }

    private void createAndShowToast() {
        inflateToastLayout();
        ToastDialog toast = new ToastDialog(getContext());
        toast.setAlignment(LayoutAlignment.BOTTOM);
        if (gravity == 1) {
            toast.setAlignment(LayoutAlignment.CENTER);
        } else if (gravity == 2) {
            toast.setAlignment(LayoutAlignment.TOP);
        }
        toast.setSize(ComponentContainer.LayoutConfig.MATCH_CONTENT, ComponentContainer.LayoutConfig.MATCH_CONTENT);
        toast.setComponent(rootLayout);
        if (cornerRadius > 0) {
            toast.setCornerRadius(AttrHelper.fp2px(cornerRadius, getContext()));
        } else {
            toast.setCornerRadius(AttrHelper.fp2px(mCornerRadius, getContext()));
        }

        if (gravity == LayoutAlignment.BOTTOM) {
            toast.setOffset(0, AttrHelper.fp2px(Constants.TOAST_OFFSET_X, getContext()));
        }
        toast.show();

    }

    private void inflateToastLayout() {
        rootLayout = LayoutScatter.getInstance(getContext()).parse(ResourceTable.Layout_styleable_layout, null, true);
        textView = (Text) rootLayout.findComponentById(ResourceTable.Id_textview);
        makeShape();
        makeTextView();
        makeIcon();
    }

    private void makeIcon() {
        int paddingVertical = (int) AttrHelper.fp2px(PADDING_VERTICAL, getContext());
        int paddingHorizontal1 = (int) AttrHelper.fp2px(PADDING_HORIZONTAL, getContext());
        int paddingNoIcon = (int) AttrHelper.fp2px(PADDING_NO_ICON, getContext());
        int iconSize = (int) AttrHelper.fp2px(ICON_SIZE, getContext());
        if (iconStart != 0) {
            try {
                Resource resource = getContext().getResourceManager().getResource(iconStart);
                PixelMapElement drawable = new PixelMapElement(resource);
                if (drawable != null) {
                    drawable.setBounds(0, 0, iconSize, iconSize);
                    textView.setAroundElementsRelative(drawable, null, null, null);
                    rootLayout.setPadding(paddingNoIcon, paddingVertical, paddingHorizontal1, paddingVertical);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } catch (NotExistException e) {
                e.printStackTrace();
            }
        }

        if (iconEnd != 0) {
            Resource resource = null;
            try {
                resource = getContext().getResourceManager().getResource(iconEnd);
                PixelMapElement drawable = new PixelMapElement(resource);
                if (drawable != null) {
                    drawable.setBounds(0, 0, iconSize, iconSize);
                    textView.setAroundElementsRelative(null, null, drawable, null);
                    rootLayout.setPadding(paddingHorizontal1, paddingVertical, paddingNoIcon, paddingVertical);

                }
            } catch (IOException e) {
                e.printStackTrace();
            } catch (NotExistException e) {
                e.printStackTrace();
            }

        }

        if (iconStart != 0 && iconEnd != 0) {

            try {
                Resource mResourceLeft = getContext().getResourceManager().getResource(iconStart);
                PixelMapElement drawableLeft = new PixelMapElement(mResourceLeft);
                Resource mResourceRight = getContext().getResourceManager().getResource(iconEnd);
                PixelMapElement drawableRight = new PixelMapElement(mResourceRight);
                if (drawableLeft != null && drawableRight != null) {
                    drawableLeft.setBounds(0, 0, iconSize, iconSize);
                    drawableRight.setBounds(0, 0, iconSize, iconSize);
                    textView.setAroundElements(drawableLeft, null, drawableRight, null);
                    rootLayout.setPadding(paddingHorizontal1, paddingVertical, paddingHorizontal1, paddingVertical);
                }

            } catch (IOException e) {
                e.printStackTrace();
            } catch (NotExistException e) {
                e.printStackTrace();
            }

        }

    }


    private void makeTextView() {
        textView.setText(text);
        if (textColor != null) {
            textView.setTextColor(textColor);
        }
        if (textSize > 0) {
            textView.setTextSize(textSize, isTextSizeFromStyleXml ? Text.TextSizeType.PX : Text.TextSizeType.VP);
        }
        if (!TextUtils.isEmpty(fontName)) {
            Font fontBuild = createFontBuild(getContext(), fontName);
            textView.setFont(fontBuild);
        }

        if (textBold) {
            textView.setFont(Font.DEFAULT_BOLD);
        }

        if (textBold && TextUtils.isEmpty(fontName)) {
            textView.setFont(Font.DEFAULT_BOLD);
        }


    }


    private void makeShape() {
        mBackgroundDrawable = new ShapeElement();
        mBackgroundDrawable.setAlpha(Constants.ALPHA);
        //默认是30 但是 rootLayout.setBackground(mBackgroundDrawable);调用了该方法  backgrund中的shape图形设置的 radius就失效了
        mBackgroundDrawable.setCornerRadius(AttrHelper.fp2px(mCornerRadius, getContext()));
        if (strokeWidth > 0) {
            mBackgroundDrawable.setStroke(AttrHelper.fp2px(strokeWidth, getContext()), RgbColor.fromArgbInt(strokeColor.getValue()));
        }
        if (cornerRadius > Constants.DEFAULT_NUMBER) {
            mBackgroundDrawable.setCornerRadius(AttrHelper.fp2px(cornerRadius, getContext()));
        }

        if (backgroundColor == null) {
            mBackgroundDrawable.setRgbColor(RgbColor.fromArgbInt(defaultBackgroundColor.getValue()));
        } else {
            mBackgroundDrawable.setRgbColor(RgbColor.fromArgbInt(backgroundColor.getValue()));
        }
        if (solidBackground) {
            mBackgroundDrawable.setAlpha(Constants.MAX_ALPHA);
        }
        rootLayout.setBackground(mBackgroundDrawable);
    }


    /**
     * 加载布局以及后续一些设置
     */
    public void show() {
        createAndShowToast();
    }


    public StyleableToast(Builder builder) {
        super(builder.context);
        this.backgroundColor = builder.backgroundColor;
        this.cornerRadius = builder.cornerRadius;
        this.iconEnd = builder.iconEnd;
        this.iconStart = builder.iconStart;
        this.strokeColor = builder.strokeColor;
        this.strokeWidth = builder.strokeWidth;
        this.solidBackground = builder.solidBackground;
        this.textColor = builder.textColor;
        this.textSize = builder.textSize;
        this.textBold = builder.textBold;
        this.fontName = builder.fontName;
        this.text = builder.text;
        this.gravity = builder.gravity;
    }


    /**
     * 传入参数
     *
     * @since 2021-03-05
     */
    public static class Builder {
        private int cornerRadius = -1;
        private Color backgroundColor;
        private Color strokeColor;
        private int strokeWidth;
        private int iconStart;
        private int iconEnd;
        private Color textColor;
        private String fontName;
        private int textSize;
        private boolean solidBackground;
        private boolean textBold;
        private String text;
        private int gravity = LayoutAlignment.BOTTOM;
        private final Context context;

        /**
         * 传入context
         *
         * @param context
         */
        public Builder(Context context) {
            this.context = context;
        }

        /**
         * 传入显示信息
         *
         * @param text
         * @return Builder对象
         */
        public Builder text(String text) {
            this.text = text;
            return this;
        }

        /**
         * 设置textColor
         *
         * @param textColor
         * @return Builder对象
         */
        public Builder textColor(Color textColor) {
            this.textColor = textColor;
            return this;
        }

        /**
         * 是否粗体
         *
         * @return Builder对象
         */
        public Builder textBold() {
            this.textBold = true;
            return this;
        }

        /**
         * 字体大小
         *
         * @param textSize
         * @return Builder对象
         */
        public Builder textSize(int textSize) {
            this.textSize = textSize;
            return this;
        }

        /**
         * 外部字体文件名称
         *
         * @param fontName
         * @return Builder对象
         */
        public Builder font(String fontName) {
            this.fontName = fontName;
            return this;
        }

        /**
         * 背景色
         *
         * @param backgroundColor
         * @return Builder对象
         */
        public Builder backgroundColor(Color backgroundColor) {
            this.backgroundColor = backgroundColor;
            return this;
        }

        /**
         * This call will make the StyleableToast's background completely solid without any opacity.
         *
         * @return Builder对象
         */
        public Builder solidBackground() {
            this.solidBackground = true;
            return this;
        }

        /**
         * 描边尺寸
         *
         * @param strokeWidth
         * @param strokeColor
         * @return Builder对象
         */
        public Builder stroke(int strokeWidth, Color strokeColor) {
            this.strokeWidth = strokeWidth;
            this.strokeColor = strokeColor;
            return this;
        }

        /**
         * cornerRadius大小
         *
         * @param cornerRadius
         * @return Builder对象
         */
        public Builder cornerRadius(int cornerRadius) {
            this.cornerRadius = cornerRadius;
            return this;
        }

        /**
         * int图片
         *
         * @param iconStart
         * @return Builder对象
         */
        public Builder iconStart(int iconStart) {
            this.iconStart = iconStart;
            return this;
        }

        /**
         * int 图片
         *
         * @param iconEnd
         * @return Builder对象
         */
        public Builder iconEnd(int iconEnd) {
            this.iconEnd = iconEnd;
            return this;
        }

        /**
         * Sets where the StyleableToast will appear on the screen
         *
         * @param gravity
         * @return Builder对象
         */
        public Builder gravity(int gravity) {
            this.gravity = gravity;
            return this;
        }


        /**
         * show
         */
        public void show() {
            StyleableToast toast = new StyleableToast(this);
            toast.show();
        }

        /**
         * 参数还原
         */
        public void recover() {
            this.text = "";
            this.cornerRadius = Constants.DEFAULT_NUMBER;
            this.backgroundColor = null;
            this.iconEnd = 0;
            this.iconStart = 0;
            this.strokeWidth = 0;
            this.solidBackground = false;
            this.textColor = new Color(Constants.DEFAULT_COLOR);
            this.textSize = 0;
            this.textBold = false;
            this.fontName = "";
        }
    }


    private Font createFontBuild(Context context, String name) {
        ResourceManager resManager = context.getResourceManager();
        RawFileEntry rawFileEntry = resManager.getRawFileEntry("resources/rawfile/" + name);
        Resource resource = null;
        OutputStream outputStream = null;
        File file = new File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES),  new StringBuffer(name).toString());
        try {
            resource = rawFileEntry.openRawFile();
            outputStream = new FileOutputStream(file);
            int index;
            byte[] bytes = new byte[Constants.BYTE];
            while ((index = resource.read(bytes)) != Constants.DEFAULT_NUMBER) {
                outputStream.write(bytes, 0, index);
                outputStream.flush();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (outputStream != null && resource != null) {
                    resource.close();
                    outputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
        Font.Builder builder = new Font.Builder(file);
        return builder.build();
    }
}
